package com.sl.ms.work.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import com.sl.ms.work.domain.enums.transportorder.TransportOrderSchedulingStatus;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sl.ms.base.api.common.MQFeign;
import com.sl.ms.oms.api.OrderFeign;
import com.sl.ms.oms.dto.OrderCargoDTO;
import com.sl.ms.oms.dto.OrderDetailDTO;
import com.sl.ms.oms.dto.OrderLocationDTO;
import com.sl.ms.transport.api.TransportLineFeign;
import com.sl.ms.work.domain.dto.TransportOrderDTO;
import com.sl.ms.work.domain.dto.request.TransportOrderQueryDTO;
import com.sl.ms.work.domain.dto.response.TransportOrderStatusCountDTO;
import com.sl.ms.work.domain.enums.WorkExceptionEnum;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskType;
import com.sl.ms.work.domain.enums.transportorder.TransportOrderStatus;
import com.sl.ms.work.entity.TransportOrderEntity;
import com.sl.ms.work.entity.TransportOrderTaskEntity;
import com.sl.ms.work.mapper.TransportOrderMapper;
import com.sl.ms.work.mapper.TransportOrderTaskMapper;
import com.sl.ms.work.service.TransportOrderService;
import com.sl.ms.work.service.TransportTaskService;
import com.sl.transport.common.constant.Constants;
import com.sl.transport.common.enums.IdEnum;
import com.sl.transport.common.exception.SLException;
import com.sl.transport.common.service.IdService;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.vo.OrderMsg;
import com.sl.transport.common.vo.TransportOrderMsg;
import com.sl.transport.common.vo.TransportOrderStatusMsg;
import com.sl.transport.domain.OrganDTO;
import com.sl.transport.domain.TransportLineNodeDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TransportOrderServiceImpl extends ServiceImpl<TransportOrderMapper, TransportOrderEntity> implements TransportOrderService {

    @Resource
    private MQFeign mqFeign;

    @Resource
    private TransportOrderTaskMapper transportOrderTaskMapper;

    @Resource
    private OrderFeign orderFeign;

    @Resource
    private TransportTaskService transportTaskService;

    @Resource
    private TransportLineFeign transportLineFeign;

    @Resource
    private IdService idService;

    @Transactional
    @Override
    public TransportOrderEntity orderToTransportOrder(Long orderId) {
        // 1. 幂等性校验   根据订单id查询关联运单是否存在  存在直接返回  因为进行幂等性的校验
        TransportOrderEntity transportOrderEntity = findByOrderId(orderId);
        if (transportOrderEntity != null) {
            return transportOrderEntity;
        }
        // 2. 根据订单id查询订单  订单数据  为空的话抛出异常
        OrderDetailDTO orderDetailDTO = orderFeign.findDetailByOrderId(orderId);
        if (ObjectUtil.isEmpty(orderDetailDTO)) {
            throw new SLException(WorkExceptionEnum.ORDER_NOT_FOUND);
        }

        // 3. 根据订单id查询 订单货物数据  如果为空 抛出异常
        OrderCargoDTO cargoDto = orderDetailDTO.getOrderDTO().getOrderCargoDto();
        if (ObjectUtil.isEmpty(cargoDto)) {
            throw new SLException(WorkExceptionEnum.ORDER_CARGO_NOT_FOUND);
        }

        // 4. 根据订单id查询 订单位置数据   如果为空  抛出异常
        OrderLocationDTO orderLocationDTO = orderDetailDTO.getOrderLocationDTO();
        if (ObjectUtil.isEmpty(orderLocationDTO)) {
            throw new SLException(WorkExceptionEnum.ORDER_LOCATION_NOT_FOUND);
        }


        // 5. 获取到 起始地点和终止地点
        Long sendAgentId = Convert.toLong(orderLocationDTO.getSendAgentId());// 转为Long类型
        Long receiveAgentId = Convert.toLong(orderLocationDTO.getReceiveAgentId());// 转为Long类型

        // 6. 定义一个调度的变量  isDispatch 来看是否需要调度
        boolean isDispatch = true; // 默认是需要调用的

        // 7. 定义一个运输路线的 实体类  TransportLineNodeDTO  默认为null
        TransportLineNodeDTO transportLineNodeDTO = null;


        // 8. 判断起始点是否相同
        if (ObjectUtil.equal(sendAgentId, receiveAgentId)) {
            // 8.1.  相同  则将isDispatch 设置为false
            isDispatch = false;
        } else {
            // 需要派送
            // 根据起始机构规划运输路线
            // 8.2.  不相同  设置运单的其他信息
            transportLineNodeDTO = transportLineFeign.queryPathByDispatchMethod(sendAgentId, receiveAgentId);

            // 看里面的路线结点  因为是派送所以是这样的
            if (transportLineNodeDTO == null || ObjectUtil.isEmpty(transportLineNodeDTO) || CollUtil.isEmpty(transportLineNodeDTO.getNodeList())) {
                throw new SLException(WorkExceptionEnum.TRANSPORT_LINE_NOT_FOUND);
            }
        }

        //创建新的运单对象
        TransportOrderEntity transportOrder = new TransportOrderEntity();
        transportOrder.setId(idService.getId(IdEnum.TRANSPORT_ORDER));
        transportOrder.setOrderId(orderId);

        transportOrder.setStartAgencyId(sendAgentId);//起始网点id
        transportOrder.setEndAgencyId(receiveAgentId);//终点网点id
        transportOrder.setCurrentAgencyId(sendAgentId);//当前所在机构id


        // 9. transportLineNodeDTO 判断运输路线是否为空  为空和不为空设置的运单数据是不一样的
        if (ObjectUtil.isNotEmpty(transportLineNodeDTO)) {
            transportOrder.setStatus(TransportOrderStatus.CREATED);
            transportOrder.setSchedulingStatus(TransportOrderSchedulingStatus.TO_BE_SCHEDULED);//调度状态(1.待调度2.未匹配线路3.已调度)
            transportOrder.setNextAgencyId(transportLineNodeDTO.getNodeList().get(1).getId());//下一个机构id
            transportOrder.setTransportLine(JSONUtil.toJsonStr(transportLineNodeDTO));//完整的运输路线
        } else {
            transportOrder.setNextAgencyId(sendAgentId);
            transportOrder.setStatus(TransportOrderStatus.ARRIVED_END);//运单状态(1.新建 2.已装车 3.运输中 4.到达终端网点 5.已签收 6.拒收)
            transportOrder.setSchedulingStatus(TransportOrderSchedulingStatus.SCHEDULED);//调度状态(1.待调度2.未匹配线路3.已调度)
        }

        transportOrder.setTotalVolume(cargoDto.getVolume());//货品总体积，单位m^3
        transportOrder.setTotalWeight(cargoDto.getWeight());//货品总重量，单位kg
        transportOrder.setIsRejection(false); //默认非拒收订单

        // 9. 保存运单
        boolean result = super.save(transportOrder);

        // 9.1 保存成功要发送消息
        if (result) {
            if (isDispatch) {
                //发送消息到调度中心，进行调度
                this.sendTransportOrderMsgToDispatch(transportOrder);
            } else {
                // 发送派件消息
                this.sendDispatchTaskMsgToDispatch(transportOrder);
                // 不需要调度  发送消息更新订单状态
                this.sendUpdateStatusMsg(ListUtil.toList(transportOrder.getId()), TransportOrderStatus.ARRIVED_END);
            }

            //发消息通知其他系统，运单已经生成
            this.sendTransportOrderCreate(transportOrder);
            return transportOrder;
        } else {

            // 9.2 不成功则抛出异常
            throw new SLException(WorkExceptionEnum.TRANSPORT_ORDER_SAVE_ERROR);
        }


    }

    /**
     * 获取运单分页数据
     *
     * @param transportOrderQueryDTO 分页参数
     * @return 运单分页数据
     */
    @Override
    public Page<TransportOrderEntity> findByPage(TransportOrderQueryDTO transportOrderQueryDTO) {
        Page<TransportOrderEntity> iPage = new Page<>(transportOrderQueryDTO.getPage(), transportOrderQueryDTO.getPageSize());

        //设置查询条件
        LambdaQueryWrapper<TransportOrderEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getId()), TransportOrderEntity::getId, transportOrderQueryDTO.getId());
        lambdaQueryWrapper.like(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getOrderId()), TransportOrderEntity::getOrderId, transportOrderQueryDTO.getOrderId());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getStatus()), TransportOrderEntity::getStatus, transportOrderQueryDTO.getStatus());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getSchedulingStatus()), TransportOrderEntity::getSchedulingStatus, transportOrderQueryDTO.getSchedulingStatus());

        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getStartAgencyId()), TransportOrderEntity::getStartAgencyId, transportOrderQueryDTO.getStartAgencyId());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getEndAgencyId()), TransportOrderEntity::getEndAgencyId, transportOrderQueryDTO.getEndAgencyId());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(transportOrderQueryDTO.getCurrentAgencyId()), TransportOrderEntity::getCurrentAgencyId, transportOrderQueryDTO.getCurrentAgencyId());
        lambdaQueryWrapper.orderByDesc(TransportOrderEntity::getCreated);

        return super.page(iPage, lambdaQueryWrapper);
    }

    /**
     * 通过订单id获取运单信息
     *
     * @param orderId 订单id
     * @return 运单信息
     */
    @Override
    public TransportOrderEntity findByOrderId(Long orderId) {
        LambdaQueryWrapper<TransportOrderEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TransportOrderEntity::getOrderId, orderId);
        return super.getOne(queryWrapper);
    }

    /**
     * 通过订单id列表获取运单列表
     *
     * @param orderIds 订单id列表
     * @return 运单列表
     */
    @Override
    public List<TransportOrderEntity> findByOrderIds(Long[] orderIds) {
        LambdaQueryWrapper<TransportOrderEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ArrayUtil.isNotEmpty(orderIds), TransportOrderEntity::getOrderId, CollUtil.toList(orderIds));
        return super.list(queryWrapper);
    }

    /**
     * 通过运单id列表获取运单列表
     *
     * @param ids 运单id列表
     * @return
     */
    @Override
    public List<TransportOrderEntity> findByIds(String[] ids) {
        return listByIds(Collections.singleton(ids));
    }

    /**
     * 根据运单号搜索运单
     *
     * @param id 运单号
     * @return 运单列表
     */
    @Override
    public List<TransportOrderEntity> searchById(String id) {
        LambdaQueryWrapper<TransportOrderEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(TransportOrderEntity::getId, id);
        return super.list(queryWrapper);
    }

    /**
     * 修改运单状态
     *
     * @param ids                  运单id列表
     * @param transportOrderStatus 修改的状态
     * @return 是否成功
     */
    @Override
    public boolean updateStatus(List<String> ids, TransportOrderStatus transportOrderStatus) {
        // 1.判断集合是否为null
        if (CollUtil.isEmpty(ids)) {
            return false;
        }

        // 2.判断是否为创建状态
        if (TransportOrderStatus.CREATED == transportOrderStatus) {
            //修改订单状态不能为 新建 状态
            throw new SLException(WorkExceptionEnum.TRANSPORT_ORDER_STATUS_NOT_CREATED);
        }

        List<TransportOrderEntity> transportOrderList;
        // 判断是否为拒收状态，如果是拒收需要重新查询路线，将包裹逆向回去
        if (TransportOrderStatus.REJECTED == transportOrderStatus) {


            // 查询运单列表
            transportOrderList = super.listByIds(ids);
            for (TransportOrderEntity transportOrderEntity : transportOrderList) {
                // 设置为拒收运单
                transportOrderEntity.setIsRejection(true);
                // 根据起始机构规划运输路线，这里要将起点和终点互换
                Long sendAgentId = transportOrderEntity.getEndAgencyId();//起始网点id
                Long receiveAgentId = transportOrderEntity.getStartAgencyId();//终点网点id

                // 默认参与调度
                boolean isDispatch = true;
                if (ObjectUtil.equal(sendAgentId, receiveAgentId)) {
                    // 相同节点，无需调度，直接生成派件任务
                    isDispatch = false;
                } else {
                    TransportLineNodeDTO transportLineNodeDTO = this.transportLineFeign.queryPathByDispatchMethod(sendAgentId, receiveAgentId);
                    if (ObjectUtil.hasEmpty(transportLineNodeDTO, transportLineNodeDTO.getNodeList())) {
                        throw new SLException(WorkExceptionEnum.TRANSPORT_LINE_NOT_FOUND);
                    }

                    // 删除掉第一个机构，逆向回去的第一个节点就是当前所在节点  因为当前就是在 abcd在d处进行退单的
                    transportLineNodeDTO.getNodeList().remove(0);
                    // 设置调度状态
                    transportOrderEntity.setSchedulingStatus(TransportOrderSchedulingStatus.TO_BE_SCHEDULED);//调度状态：待调度
                    // 这是机构id
                    transportOrderEntity.setCurrentAgencyId(sendAgentId);//当前所在机构id
                    transportOrderEntity.setNextAgencyId(transportLineNodeDTO.getNodeList().get(0).getId());//下一个机构id

                    //获取到原有节点信息
                    TransportLineNodeDTO transportLineNode = JSONUtil.toBean(transportOrderEntity.getTransportLine(), TransportLineNodeDTO.class);
                    //将逆向节点追加到节点列表中
                    transportLineNode.getNodeList().addAll(transportLineNodeDTO.getNodeList());
                    //合并成本
                    transportLineNode.setCost(NumberUtil.add(transportLineNode.getCost(), transportLineNodeDTO.getCost()));
                    transportOrderEntity.setTransportLine(JSONUtil.toJsonStr(transportLineNode));//完整的运输路线
                }
                transportOrderEntity.setStatus(TransportOrderStatus.REJECTED);

                // 判断是否需要调度
                if (isDispatch) {

                    //发送消息参与调度
                    this.sendTransportOrderMsgToDispatch(transportOrderEntity);

                } else {

                    //不需要调度，发送消息生成派件任务
                    transportOrderEntity.setStatus(TransportOrderStatus.ARRIVED_END);
                    this.sendDispatchTaskMsgToDispatch(transportOrderEntity);

                }

            }
        } else {
            // 没有被退还
            //根据id列表封装成运单对象列表
            transportOrderList = ids.stream().map(id -> {
                // TODO 发送运单跟踪消息
                //封装运单对象
                TransportOrderEntity transportOrderEntity = new TransportOrderEntity();
                transportOrderEntity.setId(id);
                transportOrderEntity.setStatus(transportOrderStatus);
                return transportOrderEntity;
            }).collect(Collectors.toList());
        }

        //批量更新数据
        boolean result = super.updateBatchById(transportOrderList);

        //发消息通知其他系统运单状态的变化
        this.sendUpdateStatusMsg(ids, transportOrderStatus);

        return result;
    }


    /**
     * 统计各个状态的数量
     *
     * @return 状态数量数据
     */
    @Override
    public List<TransportOrderStatusCountDTO> findStatusCount() {
        // 1.先让每一个枚举里面的count值都是0
        List<TransportOrderStatusCountDTO> transportOrderStatusCountDTOS = Arrays.stream(TransportOrderStatus.values()).map(transportOrderStatus -> TransportOrderStatusCountDTO.builder().status(transportOrderStatus).count(0L).statusCode(transportOrderStatus.getCode()).build()).collect(Collectors.toList());

        // 2.从数据库根据groupBy进行查询
        List<TransportOrderStatusCountDTO> statusCount = this.baseMapper.findStatusCount();

        for (TransportOrderStatusCountDTO dto : transportOrderStatusCountDTOS) {
            for (TransportOrderStatusCountDTO dtoByDb : statusCount) {
                if (Objects.equals(dtoByDb.getStatusCode(), dto.getStatusCode())) {
                    dto.setCount(dtoByDb.getCount());
                    break;
                }
            }
        }
        return transportOrderStatusCountDTOS;
    }


    /**
     * 根据运输任务id批量修改运单，其中会涉及到下一个节点的流转，已经发送消息的业务
     *
     * @param taskId 运输任务id
     * @return 是否成功
     */
    @Transactional
    @Override
    public boolean updateByTaskId(Long taskId) {
        // 1.通过运输任务查询运单id列表
        List<String> transportOrderIdList = transportTaskService.queryTransportOrderIdListById(taskId);
        // 2.判断运单列表是不是为空
        if (CollUtil.isEmpty(transportOrderIdList)) {
            return false;
        }

        // 3.查询出所有的运单信息
        List<TransportOrderEntity> transportOrderEntities = listByIds(transportOrderIdList);

        if (CollUtil.isEmpty(transportOrderEntities)) {
            return false;
        }

        for (TransportOrderEntity transportOrderEntity : transportOrderEntities) {
            // TODO 发送物流信息

            // 3.1.设置当前的agencyId设置的值为下一站的agencyId
            transportOrderEntity.setCurrentAgencyId(transportOrderEntity.getNextAgencyId());

            // 3.2.解析获取完整的路线  转为json字符串
            TransportLineNodeDTO transportLineNodeDTO = BeanUtil.toBean(transportOrderEntity.getTransportLine(), TransportLineNodeDTO.class);

            List<OrganDTO> nodeList = transportLineNodeDTO.getNodeList();
            Long nextAgencyId = null;
            // 3.3. 反向遍历  结点id 就是为了找到下一站的agencyId
            // 正常：A B C D 拒收：A B C D C B A
            for (int i = nodeList.size() - 1; i >= 0; i--) {
                Long agencyId = nodeList.get(i).getId();
                if (ObjectUtil.equal(transportOrderEntity.getCurrentAgencyId(), agencyId)) {
                    // 还要看一下是不是终点了
                    if (i == nodeList.size() - 1) {
                        // 修改状态
                        transportOrderEntity.setStatus(TransportOrderStatus.ARRIVED_END);
                        // 发布消息
                        //
                        this.sendUpdateStatusMsg(ListUtil.toList(transportOrderEntity.getId()), TransportOrderStatus.ARRIVED_END);

                        // 如果是重点站的话 下一站id就是终点id
                        nextAgencyId = nodeList.get(i).getId();
                    } else {
                        // 修改调度状态  为  待调度
                        transportOrderEntity.setSchedulingStatus(TransportOrderSchedulingStatus.TO_BE_SCHEDULED);
                        // 设置下一站的agencyId 就是 i+1
                        nextAgencyId = nodeList.get(i + 1).getId();
                    }
                    // 表示找到了 就不用再找了
                    break;
                }
            }
            // 设置下一站的网点id
            transportOrderEntity.setNextAgencyId(nextAgencyId);

            // 3.4.判断这个运单是否已经到达
            if (ObjectUtil.equal(transportOrderEntity.getStatus(), TransportOrderStatus.ARRIVED_END)) {
                // 到达终点站  就发送派件消息  就是让快递员来分拣货物了   或者说是上门等
                this.sendDispatchTaskMsgToDispatch(transportOrderEntity);

            } else {
                // 没有到终点 就发送调度消息
                this.sendTransportOrderMsgToDispatch(transportOrderEntity);
            }
        }

        // 4.修改运单的信息  也就是下一站以及当前到达这一站后 状态是怎么样的
        return updateBatchById(transportOrderEntities);
    }


    /**
     * 根据运输任务id分页查询运单信息
     *
     * @param page             页码
     * @param pageSize         页面大小
     * @param taskId           运输任务id
     * @param transportOrderId 运单id
     * @return 运单对象分页数据
     */
    @Override
    public PageResponse<TransportOrderDTO> pageQueryByTaskId(Integer page, Integer pageSize, String taskId, String transportOrderId) {
        // 首先是用的中间表来查询的
        Page<TransportOrderTaskEntity> transportOrderTaskPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<TransportOrderTaskEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ObjectUtil.isNotEmpty(taskId), TransportOrderTaskEntity::getTransportTaskId, taskId).like(ObjectUtil.isNotEmpty(transportOrderId), TransportOrderTaskEntity::getTransportOrderId, transportOrderId).orderByDesc(TransportOrderTaskEntity::getCreated);
        queryWrapper.orderByDesc(TransportOrderTaskEntity::getCreated);

        //根据运输任务id、运单id查询运输任务与运单关联关系表
        Page<TransportOrderTaskEntity> pageResult = transportOrderTaskMapper.selectPage(transportOrderTaskPage, queryWrapper);
        if (ObjectUtil.isEmpty(pageResult.getRecords())) {
            return new PageResponse<>(pageResult);
        }
        List<String> transportOrderIds = pageResult.getRecords().stream().map(TransportOrderTaskEntity::getTransportOrderId).collect(Collectors.toList());
        LambdaQueryWrapper<TransportOrderEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(TransportOrderEntity::getId, transportOrderIds);
        List<TransportOrderEntity> list = list(lambdaQueryWrapper);

        return PageResponse.of(BeanUtil.copyToList(list, TransportOrderDTO.class), page, pageSize, pageResult.getPages(), pageResult.getTotal());

    }


    /**
     * 发送运单消息到调度中，参与调度
     * 也就是发送到redis里面去了 list 和 set结构都写入了
     */
    private void sendTransportOrderMsgToDispatch(TransportOrderEntity transportOrder) {
        Map<Object, Object> msg = MapUtil.builder().put("transportOrderId", transportOrder.getId()).put("currentAgencyId", transportOrder.getCurrentAgencyId()).put("nextAgencyId", transportOrder.getNextAgencyId()).put("totalWeight", transportOrder.getTotalWeight()).put("totalVolume", transportOrder.getTotalVolume()).put("created", System.currentTimeMillis()).build();
        String jsonMsg = JSONUtil.toJsonStr(msg);
        //发送消息，延迟5秒，确保本地事务已经提交，可以查询到数据
        this.mqFeign.sendMsg(Constants.MQ.Exchanges.TRANSPORT_ORDER_DELAYED, Constants.MQ.RoutingKeys.JOIN_DISPATCH, jsonMsg, Constants.MQ.LOW_DELAY);
    }

    /**
     * 发送生成取派件任务的消息
     *
     * @param transportOrder 运单对象
     */
    private void sendDispatchTaskMsgToDispatch(TransportOrderEntity transportOrder) {
        //预计完成时间，如果是中午12点到的快递，当天22点前，否则，第二天22点前
        int offset = 0;
        if (LocalDateTime.now().getHour() >= 12) {
            offset = 1;
        }
        LocalDateTime estimatedEndTime = DateUtil.offsetDay(new Date(), offset).setField(DateField.HOUR_OF_DAY, 22).setField(DateField.MINUTE, 0).setField(DateField.SECOND, 0).setField(DateField.MILLISECOND, 0).toLocalDateTime();

        //发送分配快递员派件任务的消息
        OrderMsg orderMsg = OrderMsg.builder().agencyId(transportOrder.getCurrentAgencyId()).orderId(transportOrder.getOrderId()).created(DateUtil.current()).taskType(PickupDispatchTaskType.DISPATCH.getCode()) //派件任务
                .mark("系统提示：派件前请于收件人电话联系.").estimatedEndTime(estimatedEndTime).build();

        //发送消息
        this.sendPickupDispatchTaskMsgToDispatch(transportOrder, orderMsg);
    }

    /**
     * 发送消息到调度中心，用于生成取派件任务
     *
     * @param transportOrder 运单
     * @param orderMsg       消息内容
     */
    @Override
    public void sendPickupDispatchTaskMsgToDispatch(TransportOrderEntity transportOrder, OrderMsg orderMsg) {
        //查询订单对应的位置信息
        OrderLocationDTO orderLocationDTO = this.orderFeign.findOrderLocationByOrderId(orderMsg.getOrderId());

        //(1)运单为空：取件任务取消，取消原因为返回网点；重新调度位置取寄件人位置
        //(2)运单不为空：生成的是派件任务，需要根据拒收状态判断位置是寄件人还是收件人
        // 拒收：寄件人  其他：收件人
        String location;
        if (ObjectUtil.isEmpty(transportOrder)) {
            location = orderLocationDTO.getSendLocation();
        } else {
            location = transportOrder.getIsRejection() ? orderLocationDTO.getSendLocation() : orderLocationDTO.getReceiveLocation();
        }

        Double[] coordinate = Convert.convert(Double[].class, StrUtil.split(location, ","));
        Double longitude = coordinate[0];
        Double latitude = coordinate[1];

        //设置消息中的位置信息
        orderMsg.setLongitude(longitude);
        orderMsg.setLatitude(latitude);

        //发送消息,用于生成取派件任务
        this.mqFeign.sendMsg(Constants.MQ.Exchanges.ORDER_DELAYED, Constants.MQ.RoutingKeys.ORDER_CREATE, orderMsg.toJson(), Constants.MQ.NORMAL_DELAY);
    }

    /**
     * 发送修改状态的消息  后面 要去接受的就可以去做一些事情
     *
     * @param ids
     * @param transportOrderStatus
     */
    private void sendUpdateStatusMsg(List<String> ids, TransportOrderStatus transportOrderStatus) {
        String msg = TransportOrderStatusMsg.builder().idList(ids).statusName(transportOrderStatus.name()).statusCode(transportOrderStatus.getCode()).build().toJson();

        //将状态名称写入到路由key中，方便消费方选择性的接收消息
        String routingKey = Constants.MQ.RoutingKeys.TRANSPORT_ORDER_UPDATE_STATUS_PREFIX + transportOrderStatus.name();
        this.mqFeign.sendMsg(Constants.MQ.Exchanges.TRANSPORT_ORDER_DELAYED, routingKey, msg, Constants.MQ.LOW_DELAY);
    }


    /**
     * 发送 运单创建成功消息
     * 消费者: 订单服务  接收消息修改关联运单id
     *
     * @param transportOrder
     */
    private void sendTransportOrderCreate(TransportOrderEntity transportOrder) {
        //发消息通知其他系统，运单已经生成
        String msg = TransportOrderMsg.builder().id(transportOrder.getId()).orderId(transportOrder.getOrderId()).created(DateUtil.current()).build().toJson();
        this.mqFeign.sendMsg(Constants.MQ.Exchanges.TRANSPORT_ORDER_DELAYED, Constants.MQ.RoutingKeys.TRANSPORT_ORDER_CREATE, msg, Constants.MQ.NORMAL_DELAY);
    }


}
